package org.budo.alipay;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.budo.alipay.util.AlipayNotify;
import org.budo.alipay.util.AlipayUtil;
import org.budo.alipay.util.MD5;
import org.budo.support.mvcs.Mvcs;
import org.budo.support.spring.util.SpringUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class BudoAlipaySupport {
    protected boolean verifyNotify(Map<String, String> params, boolean isCustomerUserPay) {
        return new AlipayNotify().verifyNotify(params, isCustomerUserPay);
    }

    protected Map<String, String> buildRefundParameters(String sellerId) {
        BudoAlipayConfig conf = SpringUtil.getBean(BudoAlipayConfig.class);

        // 把请求参数打包成数组
        Map<String, String> param = new HashMap<String, String>();
        param.put("service", conf.getRefundService());
        param.put("partner", sellerId);
        param.put("_input_charset", conf.getInputCharset());
        param.put("notify_url", conf.getRefundNotifyUrl());
        param.put("seller_user_id", sellerId);
        param.put("refund_date", conf.getRefundDate());
        return param;
    }

    /**
     * 构建支付宝支付所需参数
     * 
     * https://docs.open.alipay.com/62/104743
     * 
     * @param bussinessId
     * @param desc
     * @param amount
     */
    protected Map<String, String> buildPayParameters(String outTradeNo, String desc, Double amount, boolean isCustomerUser) {
        BudoAlipayConfig conf = SpringUtil.getBean(BudoAlipayConfig.class);

        Map<String, String> params = new HashMap<String, String>();

        if (isCustomerUser) {
            params.put("partner", conf.getPartnerCustomer());
            params.put("seller_id", conf.getCustomerSellerId());
            params.put("subject", conf.getCustomerSubject());
        } else {
            params.put("partner", conf.getPartnerMerchant());
            params.put("seller_id", conf.getMerchantSellerId());
            params.put("subject", conf.getMerchantSubject());
        }

        params.put("service", conf.getPayService());
        params.put("_input_charset", conf.getInputCharset());
        params.put("payment_type", conf.getPaymentType());
        params.put("notify_url", conf.getNotifyUrl());
        params.put("return_url", conf.getReturnUrl());
        params.put("anti_phishing_key", conf.getAntiPhishingKey());
        params.put("exter_invoke_ip", conf.getExterInvokeIp());
        params.put("out_trade_no", outTradeNo);

        if (AlipayUtil.isAlipayUserAgent(Mvcs.getRequest())) {
            params.put("qr_pay_mode", "2"); // 可以直接调起确认支付页面
        }

        // 支付宝支付单位是元
        double totalFee = new BigDecimal(amount + "") //
                .divide(new BigDecimal(100)) //
                .setScale(2, RoundingMode.HALF_UP) //
                .doubleValue();

        params.put("total_fee", String.valueOf(totalFee));
        params.put("body", desc);

        log.info("#117 buildParams, desc=" + desc + ", userAgent=" + Mvcs.getUserAgent());
        return params;
    }

    /**
     * 生成签名结果
     * 
     * @param sPara 要签名的数组
     * @return 签名结果字符串
     */
    public String buildSign(Map<String, String> sPara, String md5key) {
        BudoAlipayConfig conf =SpringUtil.getBean(BudoAlipayConfig.class);

        String prestr = AlipayUtil.createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        if (conf.getSignType().equals("MD5")) {
            mysign = MD5.sign(prestr, md5key, conf.getInputCharset());
        }
        return mysign;
    }

    /**
     * 生成要请求给支付宝的参数数组
     * 
     * @param sParaTemp 请求前的参数数组
     * @return 要请求的参数数组
     */
    private Map<String, String> buildSignAndType(Map<String, String> sParaTemp, String md5key) {
        BudoAlipayConfig conf =SpringUtil.getBean(BudoAlipayConfig.class);

        // 除去数组中的空值和签名参数
        Map<String, String> sPara = AlipayUtil.parameterFilter(sParaTemp);
        // 生成签名结果
        String mysign = this.buildSign(sPara, md5key);

        // 签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", conf.getSignType());

        return sPara;
    }

    /**
     * 建立请求，以表单HTML形式构造（默认）
     * 
     * @param sParaTemp     请求参数数组
     * @param strMethod     提交方式。两个值可选：post、get
     * @param strButtonName 确认按钮显示文字
     * @return 提交表单HTML文本
     */
    public String buildRequestForm(Map<String, String> sParaTemp, String md5key, String strMethod, String strButtonName) {
        BudoAlipayConfig conf =SpringUtil.getBean(BudoAlipayConfig.class);

        // 待请求参数数组
        Map<String, String> sPara = this.buildSignAndType(sParaTemp, md5key);
        List<String> keys = new ArrayList<String>(sPara.keySet());

        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + conf.getGateway() + "_input_charset=" + conf.getInputCharset() + "\" method=\"" + strMethod + "\">");

        for (int i = 0; i < keys.size(); i++) {
            String name = (String) keys.get(i);
            String value = (String) sPara.get(name);

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }

        // submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");

        log.info("#95 sbHtml = " + sbHtml);
        return sbHtml.toString();
    }
}